Add documentation for parallel-debian
authorColin Walters <walters@verbum.org>
Mon, 17 Oct 2011 13:40:12 +0000 (09:40 -0400)
committerColin Walters <walters@verbum.org>
Mon, 17 Oct 2011 13:40:12 +0000 (09:40 -0400)
README-testing-multiroot.md [deleted file]
parallel-debian/0001-Add-support-for-subroot-option.patch [new file with mode: 0644]
parallel-debian/0001-switch_root-Add-subroot-option.patch [new file with mode: 0644]
parallel-debian/README-testing-multiroot.md [new file with mode: 0644]
parallel-debian/create-wheezy-image.sh [new file with mode: 0755]
parallel-debian/make-image-parallel.sh [new file with mode: 0755]

diff --git a/README-testing-multiroot.md b/README-testing-multiroot.md
deleted file mode 100644 (file)
index 209aaae..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-Experimenting with multiple roots
----------------------------------
-
-$ qemu-img create debian.img 600M
-$ mkfs.ext2 debian.img
-$ mkdir debian-mnt
-$ mount -o loop debian.img debian-mnt
-$ debootstrap wheezy debian-mnt
-$ chroot debian-mnt
-$ apt-get install linux-image-3.0.0
-Control-d
-$ cp debian-mnt/boot/vmlinuz* .
-$ cp debian-mnt/boot/initrd* .
-$ umount debian-mnt
-
-You now have a Debian disk image in debian.img and a kernel+initrd that are bootable with qemu.
-
-Modifying the image
--------------------
-
-The first thing I did was re-mount the image, and move almost everythig
-(/boot, /var, /etc), except lost+found to a new directory "r0".
-
-Then I started hacking on the initrd, making understand how to chroot
-to "r0".
-
-This means that after booting, every process would be in /r0 -
-including any hacktree process.  Assuming objects live in say
-/objects, we need some way for hacktree to switch things.  I think
-just chroot breakout would work.  This has the advantage the daemon
-can continue to use libraries from the active host.
-
-Note there is a self-reference here (as is present in Debian/Fedora
-etc.) - the update system would at present be shipped with the system
-itself.  Should they be independent?  That has advantages and
-disadvantages.  I think we should just try really really hard to avoid
-breaking hacktree in updates.
-
diff --git a/parallel-debian/0001-Add-support-for-subroot-option.patch b/parallel-debian/0001-Add-support-for-subroot-option.patch
new file mode 100644 (file)
index 0000000..5abf7c7
--- /dev/null
@@ -0,0 +1,148 @@
+From 0e22e86348bb356e69ed28a58e959b7fab7c43cc Mon Sep 17 00:00:00 2001
+From: Colin Walters <walters@verbum.org>
+Date: Sun, 16 Oct 2011 14:26:40 -0400
+Subject: [PATCH] Add support for subroot= option
+
+Passing this option causes the initrd to chroot() into a subdirectory of /.
+This is useful for parallel installing multiple systems in one filesystem.
+
+This relies on a patched switch_root from util-linux.
+---
+ init                     |   32 +++++++++++++++++++++-----------
+ scripts/init-bottom/udev |    5 ++---
+ scripts/local            |    6 ++++--
+ 3 files changed, 27 insertions(+), 16 deletions(-)
+
+diff --git a/init b/init
+index 445c354..3ff2750 100755
+--- a/init
++++ b/init
+@@ -49,6 +49,8 @@ export init=/sbin/init
+ export quiet=n
+ export readonly=y
+ export rootmnt=/root
++export subroot=
++export rootsubmnt=
+ export debug=
+ export panic=
+ export blacklist=
+@@ -68,6 +70,10 @@ for x in $(cat /proc/cmdline); do
+       init=*)
+               init=${x#init=}
+               ;;
++      subroot=*)
++              subroot=${x#subroot=}
++              rootsubmnt=${x#subroot=}
++              ;;
+       root=*)
+               ROOT=${x#root=}
+               case $ROOT in
+@@ -218,14 +224,18 @@ maybe_break mountroot
+ mountroot
+ log_end_msg
++if test -n "${rootsubmnt}"; then
++      rootsubmnt=${rootmnt}/${rootsubmnt}
++fi
++
+ maybe_break bottom
+ [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-bottom"
+ run_scripts /scripts/init-bottom
+ [ "$quiet" != "y" ] && log_end_msg
+ # Preserve information on old systems without /run on the rootfs
+-if [ -d ${rootmnt}/run ]; then
+-      mount -n -o move /run ${rootmnt}/run
++if [ -d ${rootsubmnt}/run ]; then
++      mount -n -o move /run ${rootsubmnt}/run
+ else
+       # The initramfs udev database must be migrated:
+       if [ -d /run/udev ] && [ ! -d /dev/.udev ]; then
+@@ -239,27 +249,27 @@ else
+ fi
+ # Move virtual filesystems over to the real filesystem
+-mount -n -o move /sys ${rootmnt}/sys
+-mount -n -o move /proc ${rootmnt}/proc
++mount -n -o move /sys ${rootsubmnt}/sys
++mount -n -o move /proc ${rootsubmnt}/proc
+ validate_init() {
+       checktarget="${1}"
+       # Work around absolute symlinks
+-      if [ -d "${rootmnt}" ] && [ -h "${rootmnt}${checktarget}" ]; then
+-              case $(readlink "${rootmnt}${checktarget}") in /*)
+-                      checktarget="$(chroot ${rootmnt} readlink ${checktarget})"
++      if [ -d "${rootsubmnt}" ] && [ -h "${rootsubmnt}${checktarget}" ]; then
++              case $(readlink "${rootsubmnt}${checktarget}") in /*)
++                      checktarget="$(chroot ${rootsubmnt} readlink ${checktarget})"
+                       ;;
+               esac
+       fi
+       # Make sure the specified init can be executed
+-      if [ ! -x "${rootmnt}${checktarget}" ]; then
++      if [ ! -x "${rootsubmnt}${checktarget}" ]; then
+               return 1
+       fi
+       # Upstart uses /etc/init as configuration directory :-/
+-      if [ -d "${rootmnt}${checktarget}" ]; then
++      if [ -d "${rootsubmnt}${checktarget}" ]; then
+               return 1
+       fi
+ }
+@@ -273,7 +283,7 @@ if [ -n "${init}" ]; then
+ fi
+ # Common case: /sbin/init is present
+-if [ ! -x "${rootmnt}/sbin/init" ]; then
++if [ ! -x "${rootsubmnt}/sbin/init" ]; then
+       # ... if it's not available search for valid init
+       if [ -z "${init}" ] ; then
+               for inittest in /sbin/init /etc/init /bin/init /bin/sh; do
+@@ -315,5 +325,5 @@ unset resume
+ unset resume_offset
+ # Chain to real filesystem
+-exec run-init ${rootmnt} ${init} "$@" <${rootmnt}/dev/console >${rootmnt}/dev/console
++exec switch_root --subroot ${subroot} ${rootmnt} ${init} "$@" <${rootsubmnt}/dev/console >${rootsubmnt}/dev/console
+ panic "Could not execute run-init."
+diff --git a/scripts/init-bottom/udev b/scripts/init-bottom/udev
+index 375dfab..7922d0f 100755
+--- a/scripts/init-bottom/udev
++++ b/scripts/init-bottom/udev
+@@ -20,9 +20,8 @@ if [ -e /etc/udev/udev.conf ]; then
+ fi
+ # move the /dev tmpfs to the rootfs
+-mount -n -o move /dev ${rootmnt}${udev_root}
++mount -n -o move /dev ${rootsubmnt}${udev_root}
+ # create a temporary symlink to the final /dev for other initramfs scripts
+ nuke /dev
+-ln -s ${rootmnt}${udev_root} /dev
+-
++ln -s ${rootsubmnt}${udev_root} /dev
+diff --git a/scripts/local b/scripts/local
+index 521e69a..25b518f 100644
+--- a/scripts/local
++++ b/scripts/local
+@@ -101,9 +101,11 @@ mountroot()
+       # FIXME This has no error checking
+       # Mount root
+       if [ "${FSTYPE}" != "unknown" ]; then
+-              mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt}
++              echo mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt}
++              mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt} || echo "FAILED TO MOUNT ROOT"
+       else
+-              mount ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt}
++              echo mount ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt}
++              mount ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt} || echo "FAILED TO MOUNT ROOT"
+       fi
+       [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-bottom"
+-- 
+1.7.6.4
+
diff --git a/parallel-debian/0001-switch_root-Add-subroot-option.patch b/parallel-debian/0001-switch_root-Add-subroot-option.patch
new file mode 100644 (file)
index 0000000..145ee70
--- /dev/null
@@ -0,0 +1,102 @@
+From fa0e7df4e3d6550f0391bb3b81b2b6ac5165439d Mon Sep 17 00:00:00 2001
+From: Colin Walters <walters@verbum.org>
+Date: Sun, 16 Oct 2011 21:01:46 -0400
+Subject: [PATCH] switch_root: Add --subroot option
+
+This is useful for parallel installing multiple operating system
+roots.  See: http://git.gnome.org/browse/hacktree
+---
+ sys-utils/switch_root.8 |    4 ++++
+ sys-utils/switch_root.c |   31 +++++++++++++++++++++----------
+ 2 files changed, 25 insertions(+), 10 deletions(-)
+
+diff --git a/sys-utils/switch_root.8 b/sys-utils/switch_root.8
+index 34ab0d0..6981852 100644
+--- a/sys-utils/switch_root.8
++++ b/sys-utils/switch_root.8
+@@ -27,6 +27,10 @@ process.
+ show help and exit
+ .IP "\fB\-V, \-\-version\fP"
+ show version number and exit
++.IP "\-\-subroot\fP"
++Instead of calling chroot into the / of the new root, instead use the
++given argument.  This helps parallel install multiple operating systems in one
++root filesystem.
+ .SH RETURN VALUE
+ .B switch_root
+diff --git a/sys-utils/switch_root.c b/sys-utils/switch_root.c
+index 2dfed71..20ae5d6 100644
+--- a/sys-utils/switch_root.c
++++ b/sys-utils/switch_root.c
+@@ -108,7 +108,7 @@ done:
+       return rc;
+ }
+-static int switchroot(const char *newroot)
++static int switchroot(const char *newroot, const char *subroot)
+ {
+       /*  Don't try to unmount the old "/", there's no way to do it. */
+       const char *umounts[] = { "/dev", "/proc", "/sys", NULL };
+@@ -141,7 +141,7 @@ static int switchroot(const char *newroot)
+               return -1;
+       }
+-      if (chroot(".")) {
++      if (chroot(subroot ? subroot : ".")) {
+               warn("failed to change root");
+               return -1;
+       }
+@@ -160,7 +160,7 @@ static int switchroot(const char *newroot)
+ static void usage(FILE *output)
+ {
+-      fprintf(output, "usage: %s <newrootdir> <init> <args to init>\n",
++      fprintf(output, "usage: %s [--subroot DIR] <newrootdir> <init> <args to init>\n",
+                       program_invocation_short_name);
+       exit(output == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+ }
+@@ -175,22 +175,33 @@ static void version(void)
+ int main(int argc, char *argv[])
+ {
+       char *newroot, *init, **initargs;
++      char *subroot = NULL;
++      int argi;
+-      if (argv[1] && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
++      if (argc < 2)
++              usage(stderr);
++
++      argi = 1;
++      if ((!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
+               usage(stdout);
+-      if (argv[1] && (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-V")))
++      if ((!strcmp(argv[1], "--version") || !strcmp(argv[1], "-V")))
+               version();
+-      if (argc < 3)
++      if (argc > 3 && argv[1] && (!strcmp(argv[1], "--subroot"))) { 
++              subroot = argv[2];
++              argi = 3;
++      }
++      if (argc <= argi+1) {
+               usage(stderr);
++      }
+-      newroot = argv[1];
+-      init = argv[2];
+-      initargs = &argv[2];
++      newroot = argv[argi];
++      init = argv[argi+1];
++      initargs = &argv[argi+1];
+       if (!*newroot || !*init)
+               usage(stderr);
+-      if (switchroot(newroot))
++      if (switchroot(newroot, subroot))
+               errx(EXIT_FAILURE, "failed. Sorry.");
+       if (access(init, X_OK))
+-- 
+1.7.6.4
+
diff --git a/parallel-debian/README-testing-multiroot.md b/parallel-debian/README-testing-multiroot.md
new file mode 100644 (file)
index 0000000..8c0a134
--- /dev/null
@@ -0,0 +1,80 @@
+
+Experimenting with multiple roots
+---------------------------------
+
+<http://wiki.debian.org/QEMU#Setting_up_a_testing.2BAC8-unstable_system>
+
+Follow the steps for making a disk image, downloading the business
+card CD, booting it in QEMU and running through the installer.
+
+Test that the image works after installation too, before you start
+modifying things below!  Remember to remove the -cdrom and -boot
+options from the installation QEMU command.
+
+Modifying the image
+-------------------
+
+You now have a disk image in debian.img, and the first partition
+should be ext4.
+
+The first thing I did was mount the image, and move almost everythig
+(/boot, /var, /etc), except lost+found to a new directory "r0".
+
+       $ mkdir /mnt/debian
+       $ modprobe nbd max_part=8
+       $ qemu-nbd --connect=/dev/nbd0 debian.qcow
+       $ mount /dev/nbd0p1 /mnt/debian/
+       $ cd /mnt/debian
+       $ mkdir r0
+       $ DIRS="bin boot dev etc lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var"
+       $ mv $DIRS r0 
+
+Now with it still mounted, we need to move on to the next part -
+modifying the initrd.  
+
+Then I started hacking on the initrd, making understand how to chroot
+to "r0".  I ended up with two patches - one to util-linux, and one to
+the "init" script in Debian's initrd.
+
+See:
+    0001-switch_root-Add-subroot-option.patch
+    0001-Add-support-for-subroot-option.patch
+
+$ git clone --depth=1 git://github.com/karelzak/util-linux.git
+$ cd util-linux
+$ patch -p1 -i ../0001-switch_root-Add-subroot-option.patch
+$ ./autogen.sh; ./configure ; make
+
+Now you have a modified "sys-utils/switch_root" binary.  Let's next
+patch the initrd and rebuild it:
+
+Make a backup:
+
+       $ mkdir initrd
+       $ cp /mnt/debian/boot/initrd.img-3.0.0-1-amd64{,.orig}
+
+Unpack, and patch:
+
+       $ zcat /mnt/debian/boot/initrd.img-3.0.0-1-amd64 | (cd initrd; cpio -d -i -v)
+       $ (cd initrd && patch -p1 -i ../0001-Add-support-for-subroot-option.patch)
+
+Repack:
+
+       $ (cd initrd; find | cpio -o -H newc) | gzip > /mnt/debian/boot/initrd.img-3.0.0-1-amd64.new
+       $ mv /mnt/debian/boot/initrd.img-3.0.0-1-amd64{.new,}
+
+Running hacktree inside the system
+----------------------------------
+
+This means that after booting, every process would be in /r0 -
+including any hacktree process.  Assuming objects live in say
+/objects, we need some way for hacktree to switch things.  I think
+just chroot breakout would work.  This has the advantage the daemon
+can continue to use libraries from the active host.
+
+Note there is a self-reference here (as is present in Debian/Fedora
+etc.) - the update system would at present be shipped with the system
+itself.  Should they be independent?  That has advantages and
+disadvantages.  I think we should just try really really hard to avoid
+breaking hacktree in updates.
+
diff --git a/parallel-debian/create-wheezy-image.sh b/parallel-debian/create-wheezy-image.sh
new file mode 100755 (executable)
index 0000000..6f8263a
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+set -e
+set -x
+
+if test -f debian.img; then
+  echo debian.img already exists
+  exit 1
+fi
+
+qemu-img create debian.img 600M
+mkfs.ext2 -q -F debian.img
+mkdir -p debian-mnt
+mount -o loop debian.img debian-mnt
+debootstrap --arch amd64 wheezy debian-mnt
+umount debian-mnt
diff --git a/parallel-debian/make-image-parallel.sh b/parallel-debian/make-image-parallel.sh
new file mode 100755 (executable)
index 0000000..b6aaa9e
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+set -e
+set -x
+
+DIRS="bin boot dev etc lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var"
+
+if ! test -f debian.img; then
+  echo need debian.img
+  exit 1
+fi
+
+mount -o loop debian.img debian-mnt
+cd debian-mnt
+if ! test -d r0; then
+  mkdir r0
+  mv $DIRS r0
+fi
+cd ..
+umount debian-mnt